package main

import (
	"fmt"
	"reflect"
)

type Person02 struct {
	Name string
	Age  int
	Sex  string
}

func (p Person02) Say(msg string) {
	fmt.Println("hello", msg)
}

func (p Person02) PrintInfo() {
	fmt.Printf("姓名：%s，年龄：%d，性别：%s\n", p.Name, p.Age, p.Sex)
}

func (p Person02) Test(i, j int, s string) {
	fmt.Println(i, j, s)
}

func main() {
	/*
		通过反射来进行方法的调用
		思路：
		step1: 接口变量 ——> 反射对象：Value
		step2: 获取对应的方法对象：MethodName()
		step3: 将方法对象进行调用：Call()
	*/
	p1 := Person02{Name: "喜羊羊", Age: 18, Sex: "男"}
	value := reflect.ValueOf(p1)
	fmt.Printf("kind: %s, type:%s\n", value.Kind(), value.Type()) //kind: struct, type:main.Person02

	methodValue := value.MethodByName("PrintInfo")
	fmt.Printf("kind:%s, type:%s\n", methodValue.Kind(), methodValue.Type()) //kind:func, type:func()

	//没有参数，进行调用
	methodValue.Call(nil) //没有参数，直接写 nil

	args1 := make([]reflect.Value, 0)
	methodValue.Call(args1) //或者创建一个空的切片也可以

	methodValue2 := value.MethodByName("Say")
	fmt.Printf("kind:%s, type:%s\n", methodValue2.Kind(), methodValue2.Type()) //kind:func, type:func(string)

	args2 := []reflect.Value{reflect.ValueOf("反射机制")}
	methodValue2.Call(args2)

	methodValue3 := value.MethodByName("Test")
	fmt.Printf("kind:%s, type:%s\n", methodValue3.Kind(), methodValue3.Type()) //kind:func, type:func(int, int, string)

	args3 := []reflect.Value{reflect.ValueOf(5), reflect.ValueOf(25), reflect.ValueOf("喜羊羊生日快乐！！！")}
	methodValue3.Call(args3)
}
